#coding=utf8
__author__ = 'alex'
from flask import g, jsonify, request, flash, url_for
from flask_mail import Message
import os
import settings
import time
import random
import json
import hmac
import redis
from pyDes import *
import sys, traceback
import urllib
from uuid import uuid4

def execute(query, page_idx, page_size):
    total = query.count()
    start, end = db_idx(page_idx, page_size)
    return total, query[start:end]

def mail(to_email, title, message):
    msg = Message(u"【艾普云】%s"%title, sender=settings.DEFAULT_MAIL_SENDER, recipients=[to_email,])
    msg.html = message
    g.mail.send(msg)

pad = lambda s, BS: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s: s[0:-ord(s[-1])]

def db_idx(page_idx, page_size):
    return (page_idx - 1) * page_size, page_idx*page_size

def tob(s, enc='utf8'):
    return s.encode(enc) if isinstance(s, unicode) else bytes(s)
def touni(s, enc='utf8', err='strict'):
    return s.decode(enc, err) if isinstance(s, bytes) else unicode(s)

def format_time(t):
    return u"%s年%s月%s日%s时%s分%s秒"%(t.year,t.month,t.day,t.hour,t.minute,t.second)

def format_date(t):
    return u"%s年%s月%s日"%(t.year,t.month,t.day)

def hash_passwd(raw_password):
    salt = "".join(random.sample('abcdefghijklmnopqrstuvwxyz1234567890ABSDXFJOHDXFH',4))
    return "$".join([salt,hmac.new(salt,tob(raw_password)).hexdigest()])

def check_passwd(raw_password,enc_password):
    salt,hmac_password=tob(enc_password).split('$')
    if hmac.new(salt,tob(raw_password)).hexdigest() == hmac_password:
        return True

def serial_maker():
    t = str(int(time.time()*1000))
    salt = "".join(random.sample('QAZXSWEDCVFRTGBNHYUJMKILOP',4))
    return "%s%s%s"%(settings.SERVER_ID,t,salt)

def read_random(length):
    import random
    save_str = "ABCDEFGHJKLMNPQRSTWXYZ2346789"
    return random.sample(save_str,length)


def generate_code_image(size, length):
    from PIL import Image, ImageDraw, ImageFilter, ImageFont
    font_path = os.path.abspath(os.path.join(os.getcwd(),"code.ttf"))
    font = ImageFont.truetype(font_path, 22)
    words = "".join(read_random(length))
    w, h = size
    font_w, font_h = font.getsize(words)
    img = Image.new('RGB',size,(255,255,255))
    draw = ImageDraw.Draw(img)
    draw.text((5,5),words,font=font,fill=(40,40,40))
    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
    return img, words


def encrypt_des(content, key):
    try:
        encryptor = des(key, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
        return encryptor.encrypt(content)
    except Exception,e:
        raise e

def decrypt_des(content, key):
    try:
        encryptor = des(key, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
        return encryptor.decrypt(content)
    except Exception,e:
        raise e


def login_required(f):
    from functools import wraps
    from flask import g, redirect, url_for, request, flash
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not g.logined:
            if request.is_xhr:
                return json_response(False, u"您还没有登陆")
            flash(request.url,category="goto")
            return redirect(url_for(settings.LOGIN_MOD))
        return f(*args, **kwargs)
    return decorated_function


def json_response(result,data):
    return jsonify(dict(r=result,info=data))


def woops(message, next="/"):
    from flask import redirect, url_for, flash
    flash(message)
    return redirect(url_for("index.show_error", next=next))


class Frame(object):
    def __init__(self, tb):
        self.tb = tb
        frame = tb.tb_frame
        self.locals = {}
        self.locals.update(frame.f_locals)

    def print_path(self):
        return touni(traceback.format_tb(self.tb, limit=1)[0])

    def print_local(self):
        return u"\n".join(["%s=%s" % (k, self.dump_value(self.locals[k])) for k in self.locals])

    def dump_value(self, v):
        try:
            return touni(str(v))
        except:
            return u"value can not serilizable"

def print_debug(ex):
    exc_type, exc_value, exc_traceback = sys.exc_info()
    frames = []
    tb = exc_traceback
    frames.append(tb.tb_frame)
    detail = u"alex error -Exception:%s\n" % ex
    while tb.tb_next:
        tb = tb.tb_next
        fm = Frame(tb)
        detail += fm.print_path()
        detail += u"\nlocals variables:\n"
        detail += fm.print_local()
        detail += u"\n-------------------------------------------------------\n"
    return detail

def pages(item_count, page_size):
    from flask import request
    base_url = request.path
    page_id = int(request.args.get("p","1"))
    def make_url(base,pid):
        base=tob(base)
        if not pid:
            return ""
        url_slice=base.split('?')
        if len(url_slice)<2:
            return base+"?p=%s"%pid
        else:
            params=dict([(lambda i:tuple(i) if len(i)<3 else (i[0],"=".join(i[1:])))(item.split("=")) for item in url_slice[1].split('&')])
            params["p"]=pid
            return "%s?%s"%(url_slice[0],urllib.urlencode(params))

    page_count=item_count/page_size+1 if item_count%page_size else item_count/page_size
    if page_count<10:
        return [(i+1,make_url(base_url,i+1)) for i in range(page_count)]
    else:
        if page_id<5:
            return [(p,make_url(base_url,p)) for p in [1,2,3,4,5,0,page_count]]
        if page_id>(page_count-4):
            return [(p,make_url(base_url,p)) for p in [1,0,page_count-4,page_count-3,page_count-2,page_count-1,page_count]]
        return [(p,make_url(base_url,p)) for p in [1,0,page_id-2,page_id-1,page_id,page_id+1,page_id+2,0,page_count]]

class Cache(object):
    def __init__(self,host,db):
        self.redis = redis.Redis(host=host,port=6379,db=db)

    def _gen_key(self,key,pub=False):
        return "aipuyun_publish_%s"%key if pub else "aipuyun_object_%s"%key

    def get(self, name, loads = json.loads):
        data = self.redis.get(self._gen_key(name))
        if data:
            return loads(data)

    def set(self, name, value, ttl=3600, dumps = json.dumps):
        if ttl:
            return self.redis.setex(self._gen_key(name), dumps(value), ttl)
        return self.redis.set(self._gen_key(name), dumps(value))

    def __getitem__(self, item):
        return self.get(item)

    def __setitem__(self, key, value):
        return self.set(key,value,ttl=0)

    def delete(self, key):
        self.redis.delete(self._gen_key(key))


    def subscribe(self, channels):
        self.pubsub = self.redis.pubsub()
        self.pubsub.subscribe(channels)

    def publish(self, channel, message):
        self.redis.publish(channel, json.dumps(message))

    def listen(self, on_message):
        for message in self.pubsub.listen():
            if message.get("type") == "message":
                on_message(message.get("channel"), json.loads(message.get("data")))

def validate_forms(form_class,form_data):
    form = form_class(form_data)
    if not form.validate():
        for name, value in request.form.iteritems():
            flash(dict(name=name, value=value),category="backinfo")
        for k,v in form.errors.iteritems():
            flash(v[0],category="error")
        return False, None
    return True, form

def add_error(message):
    flash(message,category="error")
    for name, value in request.form.iteritems():
        flash(dict(name=name, value=value),category="backinfo")


def add_success(message):
    flash(message,category="success")

def send_error(error):
    error_id = uuid4().hex
    key = "error:%s"%error_id
    g.cache.set(key,error,ttl=3600)
    return error_id

def get_error(error_id):
    key = "error:%s"%error_id
    return g.cache.get(key)

def set_lock(target_mod, params, ttl=3600*24*7):
    lock_id = uuid4().hex
    key = "lock:%s"%lock_id
    g.cache.set(key,params,ttl=ttl)
    params.update(v=lock_id)
    return "%s%s"%(settings.SERVER, url_for(target_mod,**params))

def verify_lock(lock_id):
    key = "lock:%s"%lock_id
    params = g.cache.get(key)
    if params:
        g.cache.delete(key)
    return params

def test_lock(lock_id):
    key = "lock:%s"%lock_id
    if g.cache.get(key):
        return True

def choose(pay_type, obj):
    if pay_type==0:
        return obj.monthly_price
    if pay_type==1:
        return obj.yearly_price
    if pay_type==2:
        return obj.quarter_price
    if pay_type==3:
        return obj.halfyear_price

def compute_exp(dt,pay_type,length):
    import datetime
    import calendar
    if pay_type:
        exp_dt = dt + datetime.timedelta(days=365)
    else:
        if (length+dt.month) > 11:
            year = dt.year + (length+dt.month+1)/12
            month = (length+dt.month+1)%12
            day = dt.day
        else:
            year = dt.year
            month = length+dt.month
            day = dt.day
        if month==2 and day>28:
            if calendar.isleap(year):
                day=29
            else:
                day=28
        print year,month,day
        exp_dt = datetime.datetime(year,month,day)
    return exp_dt


def send_sms(phone_number,text):
    import requests
    import logging
    text=tob(text,enc="gbk")
    r=requests.post("http://www.k8686.com/Api/BayouSmsApi.aspx",data=dict(
        func="sendsms",
        username="8006980012",
        password="",
        smstype=1,
        timerflag=0,
        mobiles=phone_number,
        message=text
    ))
    if 200<=r.status_code<300:
        logging.INFO(r.text)
